<template>
 <div>
 <svg id="twoWayTree"></svg>
 </div>
</template>
<script>
let d3 = require("../../static/d3.min.js");
 import treedemo3 from "./treedemo3.json"
 export default {
   data () {
     return {

     }
   },
   mounted(){
       this.drawing();
   },
   methods:{
       drawing(){
           var _this = this;
           var htmldom = document.getElementsByTagName('html')[0];
            var width = htmldom.clientWidth;
            var height = htmldom.clientHeight;
            
           var boxWidth = 150,
            boxHeight = 40,
            nodeWidth = 150,//控制节点之间的横向间距
            nodeHeight = 150,//控制节点之间的纵向距离
            // 动画时间
            duration = 750,
            //d3将节点大小乘以该值以计算节点之间的距离
            separation = 0.5;
            var zoom = d3.behavior.zoom()
            .scaleExtent([0.1, 1]) //用于设置最小和最大的缩放比例
            .on('zoom', function () {
                svg.attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")");
            })
            // 当 zoom 事件发生时，调用 zoomed 函数
            // ：zoomed 函数，用于更改需要缩放的元素的属性，d3.event.translate 是平移的坐标值，d3.event.scale 是缩放的值。
            .translate([`${width/2}`, `${height/2}`]);
            
            var svg = d3.select("#twoWayTree")
            .attr('width', width)
            .attr('height', height)
            .call(zoom)
            .append('g')
            // 树的左填充，以便整个根节点都在屏幕上
            .attr("transform", `translate(${width/2},${height/2})`)
            var Tree = function (svg, selector, direction) {
                this.svg = svg;
                this.selector = selector;//节点类型
                this.direction = direction;//节点方向
                
                this.tree = d3.layout.tree()
                //使用nodesize我们可以控制节点之间的间隔。如果我们使用size参数，那么d3将动态计算间隔以填充可用空间。
                //.nodesize（[节点宽度，节点高度]）
                .nodeSize([nodeWidth, nodeHeight])
                //控制节点之间的间距乘该值以计算节点之间的距离
                .separation(function () {
                    return 1.75;
                });
                
                
        };

        /**
        * Set the `children` function for the tree
        */
        Tree.prototype.children = function (fn) {
            this.tree.children(fn);
            return this;
        };

        /**
        * Set the root of the tree
        */
        Tree.prototype.data = function (data) {
            this.root = data;
            return this;
        };

        /**
        * Draw/redraw the tree
        * 画树
        */
        Tree.prototype.draw = function (source) {
            if (this.root) {
                var nodes = this.tree.nodes(this.root);
                var  links = this.tree.links(nodes);
                this.drawLinks(links, source);//画关联关系
                this.drawNodes(nodes, source);//画节点
                this.drawBtn(nodes, source);//画按钮
            } else {
                throw new Error('Missing root');
            }
            return this;
        };

        /**
        * Draw/redraw the connecting lines
        */
        Tree.prototype.drawLinks = function (links, source) {
            var diagonal = d3.svg.diagonal()
                .projection(function (d) {
                    return [d.x, (d.y+22) * self.direction];
                });
            var self = this;
            // Update links
               
                    
            var link = self.svg.selectAll("path.link." + self.selector)
                //我们传递的函数为d3提供了一个id//以便跟踪何时添加和删除数据。
                //如果树只绘制一次，则无需执行此操作
                //如基本示例所示。
                .data(links, function (d) {
                    return d.target.id;
                })
            
            // Add new links
            // Transition new links from the source's
            // old position to the links final position
            // var diagonal = d3.linkHorizontal().x(d => d.x).y(d => d.y)
            var marker =
                link.enter().append("marker")
                .attr({
                    "id":"arrow",
                    "markerUnits":"strokeWidth",
                    "viewBox":"0 0 10 10",
                    "refX":function(d){
                        return 38
                    },
                    "refY":"6",
                    "markerWidth":"10",
                    "markerHeight":"10",
                    "orient":"auto",

                })
                .append("path")
                .attr({
                    "d":function(d){
                        return "M2,2 L10,6 L2,10 L6,6 L2,2";//实在不懂不过能用
                    },
                    fill:function(d){
                        return ""
                    }
                })
            link.enter().append("path")
                .attr("class", "link " + self.selector)
              
            // Update the old links positions
            link.transition()
                .duration(duration)
                .attr({
                    "fill":"#000",
                    "stroke":"red",
                    "stroke-width":2,
                    "d":function(d){
                        return diagonal(d)
                    },
                    "marker-end":"url(#arrow)",
                });

            // Remove any links we don't need anymore
            // if part of the tree was collapsed
            // Transition exit links from their current position
            // to the source's new position
            link.exit()
                .transition()
                .duration(duration)
                .attr("d", d => {
                    const o = {
                        x: source.x,
                        y: source.y
                    };
                    return diagonal({
                        source: o,
                        target: o
                    });
                })
                .remove();

        };


        /**
        * Draw/redraw the person boxes.
        */
        Tree.prototype.drawNodes = function (nodes, source) {
            var self = this;
            console.log(self.selector)
            // Update nodes
            var node = self.svg.selectAll("g.person." + self.selector)
                // The function we are passing provides d3 with an id
                // so that it can track when data is being added and removed.
                // This is not necessary if the tree will only be drawn once
                // as in the basic example.
                .data(nodes, function (person) {
                    return person.id;
                });

            // Add any new nodes
            var nodeEnter = node.enter().append("g")
                .attr("class", "person " + self.selector)
                // Add new nodes at the right side of their child's box.
                // They will be transitioned into their proper position.
                .attr('transform', function (person) {
                    // 节点从哪里出来的位移
                    return 'translate(' + source.x0 + ',' + (self.direction * (source.y0 + boxHeight / 2)) + ')';
                })

            // Draw the rectangle person boxes.
            // Start new boxes with 0 size so that
            // we can transition them to their proper size.
            nodeEnter.append("rect")
                .attr({
                    x: 0,
                    y: 0,
                    width: 0,
                    height: 0
                })
                .style({
                    "fill":function(d){
                        if(d.depth=='0'){
                            return "#4EDC93"
                        }else{
                            return "#fff"
                        }

                    }
                });

            // Draw the person's name and position it inside the box
            nodeEnter.append("text")
                .attr("x",55)
                .attr('y',5)
                // .attr('dy','.35em')
                .attr('text-anchor',"middle")
                .attr('class', 'name')
                .text(function (d) {
                    return d.name;
                })
                .style({
                'fill-opacity': 0,
                'fill': function(d) {
                    return "#000";
                },
                'font-size': function(d) {
                    return 11;
                }})
                //股权
            nodeEnter.append("text")
                // .attr("x",-20)
                .attr({
                    "y":function(d){
                        return self.direction*-55;
                    },
                    "x":function(d){
                        return 0;
                    }
                })
                // .attr('dy','.35em')
                .attr('text-anchor',"middle")
                // .attr('class', 'id')
                .text(function (d) {
                    return d.depth==1?"88%":""
                })
                .style({
                'fill-opacity': 1,
                'fill': function(d) {
                    return "red";
                },
                'font-size': function(d) {
                    return  11;
                }})
                .on("click",function(d){
                   
                })
            // Update the position of both old and new nodes
            var nodeUpdate = node.transition()
                .duration(duration)
                .attr("transform", function (d) {
                    return "translate(" + d.x + "," + (self.direction * d.y) + ")";
                });
            // 盒子边框
            nodeUpdate.select('rect')
                .attr({
                    x: -(boxWidth / 2),
                    y: -(boxHeight / 2),
                    width: boxWidth,
                    height: boxHeight,
                    rx: "6",//圆角
                })
            // Move text to it's proper position
            // 盒子内部文本
            nodeUpdate.select('text')
                .attr("dx", -(boxWidth / 2) + 10)
                .style('fill-opacity', 1)
                .style('vertical-align', 'middle');

            // Remove nodes we aren't showing anymore
            var nodeExit = node.exit()
                .transition()
                .duration(duration)
                .attr("transform", function (d) {
                    return 'translate(' + source.x + ',' + (self.direction * (source.y + boxHeight / 2)) + ')';
                })
                .remove();

            // Shrink boxes as we remove them
            nodeExit.select('rect')
                .attr({
                    x: 0,
                    y: 0,
                    width: 0,
                    height: 0
                });

            // Fade out the text as we remove it
            nodeExit.select('text')
                .style('fill-opacity', 0)
                .attr('dx', 0);

            // a(nodeEnter, self, source)
            // Stash the old positions for transition.
            nodes.forEach(function (person) {
                person.x0 = person.x;
                person.y0 = person.y;
            });

        };
        Tree.prototype.drawBtn = function (nodes, source) {
            var self = this;

            // Update nodes
            var node = self.svg.selectAll("g.btn." + self.selector)
                .data(nodes, function (person) {
                    return person.id;
                });
            // // Add any new nodes
            var nodeEnter = node.enter().append("g")
                .attr("class", "btn " + self.selector)
                // Add new nodes at the right side of their child's box.
                // They will be transitioned into their proper position.
                .attr('transform', function (person) {
                    // 节点从哪里出来的位移
                    return 'translate(' + source.x0 + ',' + (self.direction * (source.y0 + boxHeight / 2)) + ')';
                })
                .on('click', function (person, ...event) {
                    if (this.childNodes[1].innerHTML === '+') {
                        this.childNodes[1].innerHTML = '-'
                    } else {
                        this.childNodes[1].innerHTML = '+'
                    }
                    self.togglePerson(person);
                });

            // Draw the rectangle person boxes.
            // Start new boxes with 0 size so that
            // we can transition them to their proper size.
            nodeEnter.append("circle")
                .attr({
                    x: 0,
                    y: 0,
                    r: 0,
                })
            nodeEnter.append("text")
                .attr("x", "0")
                .attr("dy", function (d) {
                    if (self.direction === -1) {
                        return -12
                    } else {
                        return 26
                    }
                })
                .attr('r', 80)
                .attr("text-anchor", "middle")
                // .style("fill", "rgba(0, 0, 0, 0.15)")
                // .style('font-size', '22px')
                .text(function (d) {
                    if (!d.depth) {
                        return ''
                    }
                    if (self.direction === -1) {
                        if (d._parents && d._parents.length) {
                            return d.collapsed ? '+' : '-'
                        } else {
                            return "";
                        }
                    } else {
                        if (d._children && d._children.length) {
                            return d.collapsed ? '+' : '-'
                        } else {
                            return "";
                        }
                    }
                })
                .style('fill-opacity', 0);



            // // Update the position of both old and new nodes
            var nodeUpdate = node.transition()
                .duration(duration)
                .attr("transform", function (d) {
                    return "translate(" + d.x + "," + (self.direction * d.y) + ")";
                });
            nodeUpdate.select('circle')
                .attr("cx", 0)
                .attr("cy", function (d) {
                    if (self.direction === -1) {
                        return -20
                    } else {
                        return 20
                    }
                })
                .attr("r", function (d) {
                    if (!d.depth) {
                        return 0
                    }
                    if (self.direction === -1) {
                        return d._parents && d._parents.length ? 10 : 0;
                    } else {
                        return d._children && d._children.length ? 10 : 0;
                    }
                })
            nodeUpdate.select('text').style('fill-opacity', 1)


            // Remove nodes we aren't showing anymore
            var nodeExit = node.exit()
                .transition()
                .duration(duration)
                .attr("transform", function (d) {
                    return 'translate(' + source.x + ',' + (self.direction * (source.y + boxHeight / 2)) + ')';
                })
                .remove();
            // // Shrink boxes as we remove them
            nodeExit.select('circle')
                .attr({
                    x: 0,
                    y: 0,
                    r: 0,
                });

            // Fade out the text as we remove it
            nodeExit.select('text')
                .style('fill-opacity', 0)
            nodes.forEach(function (person) {
                person.x0 = person.x;
                person.y0 = person.y;
            });

        };
        /**
        * Update a person's state when they are clicked.
        * 点击的时候改变折叠的状态
        */

        Tree.prototype.togglePerson = function (person, direction) {

            // Don't allow the root to be collapsed because that's
            // silly (it also makes our life easier)
            if (person === this.root) {
                return '';
            } else {
                if (person.collapsed) {
                    person.collapsed = false;
                } else {
                    collapse(person);
                }
                this.draw(person);
            }
        };
        //递归附上collapsed属性
        function collapse(person) {
            person.collapsed = true;
            if (person._parents) {
                person._parents.forEach(collapse);
            }
            if (person._children) {
                person._children.forEach(collapse);
            }
        }
        //父节点
        var ancestorTree = new Tree(svg, 'ancestor', -1);
        ancestorTree.children(function (person) {
            if (person.collapsed) {
                return;
            } else {
                return person._parents;
            }
        });
        //子节点
        var descendantsTree = new Tree(svg, 'descendant', 1);
        descendantsTree.children(function (person) {
            if (person.collapsed) {
                return;
            } else {
                return person._children;
            }
        });
        var ancestorRoot = _this.rootProxy(treedemo3);
        var descendantRoot = _this.rootProxy(treedemo3);
            ancestorRoot._parents.forEach(collapse);
        // Start with only one generation of descendants showing
        descendantRoot._children.forEach(collapse);

        // Set the root nodes
        ancestorTree.data(ancestorRoot);
        descendantsTree.data(descendantRoot);

        // Draw the tree
        ancestorTree.draw(ancestorRoot);//上半部分的树
        descendantsTree.draw(descendantRoot);//下半部分的树

       },
       rootProxy(root) {
            return {
                forward:root.forward,
                name: root.name,
                id: root.id,
                x0: 0,
                y0: 0,
                _children: root._children,
                _parents: root._parents,
                collapsed: false,
                root_parents: false,
                root_children: false
            };
        }
   }
 }
</script>

<style lang='less'>
    
    .person rect {
        fill: #fff;
        stroke: #E6E6E6;
        stroke-width: 2px;
    }
    .link {
        fill: none;
        stroke:#E6E6E6;
        stroke-width: 1.5px;
    }

    .btn circle {
        stroke: #E6E6E6;
        fill: #fff;
    }
</style>
